package service

import (
	"crypto/tls"
	"fmt"
	"gitee/com.xiaoxin/go-send/model"
	"io"
	"net/http"
	"strings"
	"sync"
)

type HttpService interface {
	Request(req model.RequestInfo) model.ResponseInfo
}

var (
	_        HttpService = (*httpService)(nil)
	srv      HttpService
	httpOnce sync.Once
)

type httpService struct {
}

func NewHttpService() HttpService {
	httpOnce.Do(func() {
		srv = &httpService{}
	})
	return srv
}

func (s *httpService) Request(req model.RequestInfo) model.ResponseInfo {
	client := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true,
			},
		},
	}
	var responseInfo = model.ResponseInfo{}
	requestUrl := parseRequestUrl(req.RequestUrl, req.RequestPathParam, req.RequestParam)
	fmt.Println(requestUrl)
	requestMethod := req.RequestMethod
	if len(requestMethod) == 0 {
		requestMethod = "GET"
	}
	request, err := http.NewRequest(requestMethod, requestUrl, strings.NewReader(req.RequestBody))
	if err != nil {
		responseInfo.ResponseCode = 500
		responseInfo.ResponseBody = err.Error()
		return responseInfo
	}
	setHeader(request, req.RequestHeader, req.RequestType)
	resp, err := client.Do(request)
	if err != nil {
		responseInfo.ResponseCode = 500
		responseInfo.ResponseBody = err.Error()
		return responseInfo
	}
	defer func(Body io.ReadCloser) {
		_ = Body.Close()
	}(resp.Body)
	responseInfo.ResponseCode = resp.StatusCode
	for key, values := range resp.Header {
		for _, value := range values {
			responseInfo.ResponseHeader = append(responseInfo.ResponseHeader, model.Property{
				Key:   key,
				Value: value,
			})
		}
	}
	bodyBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		responseInfo.ResponseCode = 500
		responseInfo.ResponseBody = err.Error()
		return responseInfo
	}
	responseInfo.ResponseBody = string(bodyBytes)
	return responseInfo
}

func setHeader(request *http.Request, requestHeader []model.Property, requestType string) {
	if len(requestType) == 0 {
		requestType = "0"
	}
	switch requestType {
	case "1":
		request.Header.Set("Content-Type", "application/atom+xml")
	case "2":
		request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	default:
		request.Header.Set("Content-Type", "application/json")
	}
	request.Header.Set("Accept", "*/*")
	request.Header.Set("Accept-Charset", "utf-8")
	if len(requestHeader) > 0 {
		for _, header := range requestHeader {
			if header.IsValid() {
				request.Header.Set(header.Key, header.Value)
			}
		}
	}
}

func parseRequestUrl(requestUrl string, requestPathParam []model.Property, requestParam []model.Property) string {
	if len(requestPathParam) == 0 && len(requestParam) == 0 {
		return requestUrl
	}
	parseUrl := requestUrl
	for _, pathParam := range requestPathParam {
		if pathParam.IsValid() {
			parseUrl = strings.ReplaceAll(parseUrl, pathParam.Key, pathParam.Value)
		}
	}
	hasQuestionMark := strings.Contains(requestUrl, "?")
	for _, param := range requestParam {
		if param.IsValid() {
			if hasQuestionMark {
				parseUrl = parseUrl + "&"
			} else {
				parseUrl = parseUrl + "?"
				hasQuestionMark = true
			}
			parseUrl = parseUrl + param.Key + "=" + param.Value
		}
	}
	return parseUrl
}
